package com.seata.demo.service.impl;

import java.math.BigDecimal;

import com.seata.demo.common.exception.AppException;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.seata.demo.service.BusinessService;
import com.seata.demo.service.OrderService;
import com.seata.demo.service.client.AccountServiceClient;
import com.seata.demo.service.client.StorageServiceClient;
import com.seata.demo.common.dto.CommodityDTO;
import com.seata.demo.common.res.Resp;

import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.GlobalTransactionContext;
import lombok.extern.slf4j.Slf4j;

/**
* 业务入口
* 使用 @GlobalTransactional 注解开启一个全局事务，此注解下的方法成为“TM”（事务管理者）。
* “TM”会向“TC”（事务协调器，即seata server端）发起一个请求，声明自己开启了一个全局事务，“TC”会生成一个全局事务ID（XID）并返回。
* 在这个全局事务期间，其他被调用的服务（RM即资源管理者）也会知道自己的事务属于这个全局事务，并把自己的事务作为一个分支事务，注册到“TC”，同时也会把自己的分支事务执行情况告诉“TC”。
* @author  zg
* @date 2021年2月9日
*/
@AllArgsConstructor
@Slf4j
@Service
public class BusinessServiceImpl implements BusinessService {
    
    private StorageServiceClient storageServiceClient;
    private AccountServiceClient accountServiceClient;
    private OrderService orderService;

    @GlobalTransactional//开启一个全局事务
    @Override
    public Resp<?> purchase(String userId, String commodityCode, int commodityCount) {
        /*String xid = RootContext.getXID();
        String xid1 = GlobalTransactionContext.getCurrentOrCreate().getXid();
        log.info("用户购买商品，xid={}, xid1={}, userId={}, commodityCode={}, commodityCount={}", xid, xid1, userId, commodityCode, commodityCount);*/
        String xid = RootContext.getXID();
        // 1. 调用storage服务扣减商品库存 -------------------------------------------------------
        log.info("1.调用storage服务扣减商品库存[{}]", xid);
        Resp<CommodityDTO> deductInventoryRes = storageServiceClient.deductInventory(commodityCode, commodityCount);
        if(deductInventoryRes.getCode() != 0) {
            log.warn("扣减商品库存失败[{}]！errMsg={}, userId={}, commodityCode={}, deductCount={}", xid, deductInventoryRes.getMsg(), commodityCode, commodityCount);
            return Resp.error("商品不存在");
        }
        
        //2. 调用account服务扣减用户余额 -------------------------------------------------------
        log.info("2. 调用account服务扣减用户余额[{}]", xid);
        CommodityDTO commodity = deductInventoryRes.getData();//商品信息
        log.info("商品信息[{}]：{}", xid, JSON.toJSONString(commodity, SerializerFeature.WriteMapNullValue));
        BigDecimal price = commodity.getPrice();//商品单价
        BigDecimal commodityTotalPrice = price.multiply(new BigDecimal(commodityCount));//商品总价
        Resp<?> deductBalanceRes = accountServiceClient.deductBalance(userId, commodityTotalPrice);
        if(deductBalanceRes.getCode() != 0) {
            log.info("用户账户扣款失败[{}]！errMsg={}, userId={}", xid, deductBalanceRes.getMsg(), userId);
            throw new AppException(deductBalanceRes.getMsg());
        }

        //3. 创建订单  ----------------------------------------------------------------------
        log.info("3. 创建订单[{}]", xid);
        Resp<?> createOrderRes =  orderService.create(userId, commodityCode, commodityCount, commodity.getPrice(), commodityTotalPrice);
        return createOrderRes;
    }
    
}
